/***************************************************************
 * Name:      Structures.h
 * Purpose:   Defines the Structures used in GanitSheets
 * Author:    Milind Gupta (milind.gupta@gmail.com)
 * Website:   https://code.google.com/p/ganitsheets/
 * Created:   2011-03-02
 * Copyright: Milind Gupta ()
 * License:   Apache License 2.0
 **************************************************************/

#ifndef __GS_STRUCTURES_H
#define __GS_STRUCTURES_H

#include <string>
#include "wx/grid.h"
#include "Globals.h"
#include "CoreStructs.h"

// This class should not be instantiated or allocated memory using new. If done then
// memory deallocation needs to be addressed
// Memory deallocation of the instances returned by idList or idListIterator
// of this class is handled by those classes automatically
class idCard
{
    public:
        idCard(std::string Name, int Value);    // Constructor
        std::string idName;
        int idVal;
};

class idList : public listManager<idCard>
{
    public:
        class idCard *AddID(std::string idName, int idVal=wxNewId());
        class idCard *getIDbyName(std::string idName);
        class idCard *getIDbyVal(int idVal);
};

class spreadSheet
{
    public:

        int WXIDPanel();
        int WXIDGrid();
        std::string sheetName();  // unique name defined by user and can be changed
        shtSize sheetSize();
        wxGrid *sheetGrid();
        wxPanel *sheetPanel();
        std::string sheetID();   // custom unique ID generated for each sheet to include in formulas
                                // This will never change
        bool setSheetName(std::string name);
        static bool evaluate;
        // Main interface class for all outside code to access a single cell
        // This class should take care of creating and removing cells in the memory structure
        // The constructors of this class are private so its instances are only created and
        // returned by methods in the spreadSheet class and by itself
        class cell
        {
            // Cell manager class
            public:
                unsigned int row();
                unsigned int column();
                std::string value();
                bool setValue(std::string value);
                std::string lastEval();
                spreadSheet *parent();
                cell *nextCellInRow();
                cell *prevCellInRow();
                cell *nextCellInColumn();
                cell *prevCellInColumn();
                friend class spreadSheet;
            private:
                cell()  {}  // Don't allow anyone to create
                cell(spreadSheet *parent, unsigned int row, unsigned int column);
                unsigned int Row,Column;
                spreadSheet *Parent;
        };
        class cell *getCell(unsigned int row, unsigned int column);  // function to return the cell object
        friend class spreadSheetList;
        friend class listManager<spreadSheet>;
    private:
        spreadSheet();
        ~spreadSheet();
        // Forward declarations
        class cellsStruct;
        class cellStruct;
        std::string SheetName;  // unique name defined by user and can be changed
        shtSize SheetSize;
        wxGrid *SheetGrid;
        wxPanel *SheetPanel;
        std::string SheetID;   // custom unique ID generated for each sheet to include in formulas
                                // This will never change
        int wxIDPanel;        // id of wx Panel
        int wxIDGrid;          // id of the wxGrid
        // This is the interface class to access the cells stored in memory
        // Only non empty cells and referenced are stored in the data structure
        class cellsStruct
        {
            public:
                cellsStruct(spreadSheet *parent);                    // Constructor
                class cellStruct *getCell(unsigned int row, unsigned int column);
                class cellStruct *addCell(unsigned int row, unsigned int column);
                class cellStruct *firstCellInRow(unsigned int row);
                class cellStruct *firstCellInColumn(unsigned int column);
                bool removeCell(unsigned int row, unsigned int column);
            private:
                unsigned long count;        // Contains number of cells
                spreadSheet *parent;
                cellsStruct() {}
                class firstCellList
                {
                    public:
                        firstCellList();
                        cellStruct *firstCell;
                        firstCellList *prevIndex;
                        firstCellList *nextIndex;
                };
                class firstCellList *rowFirstsIndex1;
                class firstCellList *columnFirstsIndex1;
        };
        // This class represent a cell stored in the memory
        class cellStruct
        {
            public:
                std::string value;
                std::string lastEval;
                std::string fastValue;  // The value string updated with cell pointers in the cell lookup table rather than their spreadsheet identifiers
                unsigned int row();
                unsigned int column();
                class cellStruct *prevCellInRow();
                class cellStruct *nextCellInRow();
                class cellStruct *prevCellInColumn();
                class cellStruct *nextCellInColumn();
                bool isEmpty();
                spreadSheet *parent();
                friend class spreadSheet::cellsStruct;
            private:
                cellStruct() {}
                cellStruct(spreadSheet *parent, unsigned int row, unsigned int column);
                unsigned int Row,Column;    // To indicate the row/column of the cell
                spreadSheet *parentSheet;
                class cellStruct *PrevCellInRow;    // linked cell may not be consecutive to this one
                class cellStruct *NextCellInRow;    // linked cell may not be consecutive to this one
                class cellStruct *PrevCellInColumn; // linked cell may not be consecutive to this one
                class cellStruct *NextCellInColumn; // linked cell may not be consecutive to this one
        };
        class cellsStruct *Cells;
};

class spreadSheetList : public listManager<spreadSheet>
{
    public:
        class spreadSheet *AddSheet(wxGrid *sheetGrid, wxPanel *sheetPanel, \
                int wxIDPanel, int wxIDGrid, shtSize *SheetSize=(&defaultSheetSize), \
                std::string Name="");
        class spreadSheet *getSheetbyName(std::string Name);
        class spreadSheet *getSheetbywxIDPanel(int wxIDVal);
        class spreadSheet *getSheetbywxIDGrid(int wxIDVal);
        friend class GanitSheetsFrame;
    private:
        class spSheetIDList *idList;
        spreadSheetList();     // Private constructor to allow only GanitSheetsFrame to construct it
};

class spSheetID
{
    public:
        std::string sheetID;
        class spreadSheet *spSheet;
        friend class spSheetIDList;
    private:
        spSheetID() {}    // private constructor
};

class spSheetIDList : public listManager<spSheetID>
{
    public:
        spSheetID *AddItem();   // Override the AddItem method of template
        std::string getUniqueID();
        friend class spreadSheetList;
    private:
        spreadSheetList *spSheets;
        spSheetIDList(spreadSheetList *spSheets);        // Constructor
        spSheetIDList() {}      // Empty constructor not allowed
};

#endif
